import { defineComponent, markRaw, computed, reactive } from 'vue'
import ItemNode from '../../ItemNode/ItemNode'
import classes from '../../ItemNode/ItemNode.module.css'
import {
  ElText,
  ElInput,
  ElUpload,
  ElButton,
  ElSwitch,
  ElFormItem,
  ElSelect,
  ElOption,
  ElInputNumber,
  ElIcon
} from 'element-plus'
import { config } from '../../request/request'
import requestRaw from '../../request/request?raw'
import { state } from '../../store/store.js'
import { generateRule } from '../../utils'
import CodeEditor from '../../panel/CodeEditor.vue'
import { UploadFilled } from '@element-plus/icons-vue'
import Tip from '../../panel/Tip.vue'

export default class NUpload extends ItemNode {
  isNUpload = true
  isFormNode = true

  constructor(node?: NUpload) {
    super(node)

    if (!node) {
      this.path = './components/NUpload/NUpload.tsx'
      this.name = '上传'

      this.props.field = `${NUpload.name.replace(/^N(\w)/, (match, p1) => p1.toLowerCase())}_${this.uuid.split('-').at(0)}`
      this.props.value = [] as Array<{ name: string; url: string }>
      this.props.label = ''
      this.props.ruleMessage = '请选择文件'
      this.props.ruleType = 'none'
      this.props.dataFn = 'function (res) {\n  return String\n}'
      this.props.action = ''
      this.props.tip = ''
      this.props.multiple = false
      this.props.drag = false
      this.props.name = 'file'
      this.props.limit = null
      this.props.changeFn = `function (value) {\n  value\n}`
    }

    const rulesOptions = reactive([
      {
        label: '无验证',
        value: 'none'
      },
      {
        label: '默认验证',
        value: 'default'
      }
    ])

    const pComponent = this.component
    this.component = markRaw(
      defineComponent(
        (props) => {
          const rule = computed(() => generateRule(this.props.ruleType, this.props.ruleMessage))

          const onSuccess = (response, uploadFile, uploadFiles) => {
            try {
              uploadFiles.forEach((element) => {
                if (element.response) {
                  if (!state) return

                  const resData = eval(`(${this.props.dataFn})`)(element.response)

                  element.url = resData
                }
              })
            } catch (e) {
              console.log(e)
            }
          }

          const onChange = (value) => {
            if (state) eval(`(${this.props.changeFn})`)(value)
          }

          return () => (
            <pComponent>
              <ElFormItem label={this.props.label} prop={this.props.field} rules={rule.value}>
                {/* fileList对象引用地址不能变 */}
                <ElUpload
                  v-model:fileList={this.props.value}
                  style={{ width: '100%' }}
                  name={this.props.name}
                  action={
                    this.props.action.includes('http')
                      ? this.props.action
                      : config.baseUrl + this.props.action
                  }
                  headers={{ Authorization: config.token }}
                  multiple={this.props.multiple}
                  limit={this.props.limit}
                  drag={this.props.drag}
                  onSuccess={onSuccess}
                  onChange={() => onChange(this.props.value)}
                >
                  {{
                    default: () =>
                      this.props.drag ? (
                        <ElIcon size={70} color="var(--el-text-color-regular)">
                          <UploadFilled />
                        </ElIcon>
                      ) : (
                        <ElButton type="primary">上传</ElButton>
                      ),
                    tip: () => (
                      <div style={{ color: 'var(--el-text-color-regular)' }}>{this.props.tip}</div>
                    )
                  }}
                </ElUpload>
              </ElFormItem>
            </pComponent>
          )
        },
        {
          name: 'NUpload'
        }
      )
    )

    const pView = this.view
    this.view = markRaw(
      defineComponent((props) => {
        return () => (
          <pView>
            <this.component style={{ transform: 'scale(0.6)' }}></this.component>
          </pView>
        )
      })
    )

    const pParams = this.params
    this.params = markRaw(
      defineComponent(() => {
        return () => (
          <pParams>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                表单字段
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.field} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                上传地址
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.action} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                接口数据处理函数
                <Tip content={'需返回文件url'}></Tip>
              </ElText>
              <div class={classes['params-item-content']}>
                <CodeEditor
                  modelValue={this.props.dataFn}
                  onUpdate:modelValue={(v) => (this.props.dataFn = v || '')}
                ></CodeEditor>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                上传的文件字段名
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.name} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                标签
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.label} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                多选
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch v-model={this.props.multiple} size="small"></ElSwitch>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                上传文件数量
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInputNumber v-model={this.props.limit} min={1} size="small"></ElInputNumber>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                拖拽上传
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSwitch v-model={this.props.drag} size="small"></ElSwitch>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                提示内容
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.tip} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                验证规则
              </ElText>
              <div class={classes['params-item-content']}>
                <ElSelect v-model={this.props.ruleType} size="small" teleported={false}>
                  {() =>
                    rulesOptions.map((item) => (
                      <ElOption key={item.value} label={item.label} value={item.value}></ElOption>
                    ))
                  }
                </ElSelect>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                验证消息
              </ElText>
              <div class={classes['params-item-content']}>
                <ElInput v-model={this.props.ruleMessage} size="small"></ElInput>
              </div>
            </div>
            <div class={classes['params-item']}>
              <ElText class={classes['params-item-label']} type="info">
                值变化处理函数
                <Tip content={'值变化后调用；可访问全局状态变量state，value：组件的值'}></Tip>
              </ElText>
              <div class={classes['params-item-content']}>
                <CodeEditor
                  modelValue={this.props.changeFn}
                  onUpdate:modelValue={(v) => (this.props.changeFn = v || '')}
                ></CodeEditor>
              </div>
            </div>
          </pParams>
        )
      })
    )
  }

  toVue(): SfcObj {
    const sfcObj = super.toVue()
    const name = sfcObj.name
    const [uuid0, uuid1] = this.uuid.split('-')
    const valueVar = `${name}_${uuid0}_value`
    const ruleVar = `${name}_${uuid0}_rule`
    const onSuccessVar = `${name}_${uuid0}_onSuccess`
    const onChangeVar = `${name}_${uuid0}_onChange`

    const ruleStr = JSON.stringify(generateRule(this.props.ruleType, this.props.ruleMessage))

    sfcObj.imports = {
      ...sfcObj.imports,
      vue: {
        ref: 'ref'
      },
      ['element-plus']: {
        ElUpload: 'ElUpload',
        ElFormItem: 'ElFormItem',
        ElIcon: 'ElIcon'
      },
      ['@element-plus/icons-vue']: {
        UploadFilled: 'UploadFilled'
      },
      ['./imports/request.js']: {
        config: 'config'
      },
      ['./imports/store.js']: {
        state: 'state'
      }
    }

    sfcObj.importFiles = {
      ...sfcObj.importFiles,
      'request.js': requestRaw
    }

    sfcObj.script = `
${sfcObj.script}
const ${valueVar} = ref([])
const ${ruleVar} = ref(${ruleStr})

const ${onSuccessVar} = (response, uploadFile, uploadFiles) => {
  uploadFiles.forEach((element) => {
    if (element.response) {
      const resData = (${this.props.dataFn || '() => {}'})(element.response)
      element.url = resData
    }
  })
}

const ${onChangeVar} = (value) => {
  (${this.props.changeFn})(value)
}
      `

    sfcObj.template = sfcObj.template.replace(
      '<slot></slot>',
      `
  <ElFormItem label="${this.props.label}" prop="${this.props.field}" :rules="${ruleVar}">
    <ElUpload
      v-model:fileList="${valueVar}"
      style="width: 100%;"
      name="${this.props.name}"
      :action="${
        this.props.action.includes('http')
          ? `'${this.props.action}'`
          : `config.baseUrl + '${this.props.action}'`
      }"
      :headers="{ Authorization: config.token }"
      :multiple="${this.props.multiple}"
      :limit="${this.props.limit}"
      :drag="${this.props.drag}"
      :on-success="${onSuccessVar}"
      :on-change="() => ${onChangeVar}(${valueVar})"
    >
      ${
        this.props.drag
          ? `<ElIcon :size="70" color="var(--el-text-color-regular)"><UploadFilled /></ElIcon>`
          : '<ElButton type="primary">上传</ElButton>'
      }
      <template #tip>
        <div style="color: var(--el-text-color-regular);">${this.props.tip}</div>
      </template>
    </ElUpload>
  </ElFormItem>
      `
    )

    return sfcObj
  }
}
